#include "function_s.h"
#include <func.h>

int cd_s(int peerfd,const char* pthname)
{
    char buf[1024]={0};
    int ret;
    if(strlen(pthname)!=0){
        ret=chdir(pthname);
        if(ret==-1) return -1;
    }
    getcwd(buf,1024);
    ret = send(peerfd,buf,strlen(buf)+1,MSG_WAITALL);
    if(ret==0){
        return 0;
    }else if(ret==-1){
        return -1;
    }else return 1;
}

int ls_s(int peerfd,const char* pthname)
{
    DIR* pdir;
    char buf[1024];
    if(strlen(pthname)!=0){
        pdir = opendir(pthname);
    }else {
        memset(buf,0,1024);
        getcwd(buf,1024);
        pdir=opendir(buf);
    }
    if(pdir==NULL) return -1;
    struct dirent* pdirent;
    int ret;
    errno=0;
    int length;
    while((pdirent = readdir(pdir)) != NULL) {
        memset(buf,0,1024);
        if(errno!=0){
            return -1;
        }
        strcpy(buf,pdirent->d_name);
        if (buf[0] == '.') {
            continue;
        }
        int length=strlen(buf);
        ret=send(peerfd,&length,4,MSG_WAITALL);
        if(ret<=0) return ret;
        ret=send(peerfd,buf,strlen(buf), MSG_WAITALL);
        puts(buf);
        if(ret<=0) return ret;
        errno=0;
    }
    length=-1;
    ret=send(peerfd,&length,4,MSG_WAITALL);
    if(ret!=1) return ret;
    closedir(pdir);
    return 1;
}

int ll_s(int peerfd,const char* pthname)
{
    DIR* pdir;
    char tt[1024]={0};
    if(strlen(pthname)!=0){
        pdir = opendir(pthname);
        strcpy(tt,pthname);
    }else {
        getcwd(tt,1024);
        pdir=opendir(tt);
    }
    if(pdir==NULL) return -1;
    struct dirent* pdirent;
    struct stat statbuf;
    errno = 0;
    char buf[1024];
    int ret;
    int length;
    while((pdirent = readdir(pdir)) != NULL) {
        if(errno!=0) return -1;
        char *name = pdirent->d_name;
        char buf1[1024]={0};
        sprintf(buf1, "%s/%s", tt, name);
        int retval = stat(buf1, &statbuf);
        if(retval==-1) return -1;
        memset(buf,0,1024);
        switch (statbuf.st_mode & S_IFMT) {
        case S_IFREG:   strcat(buf,"-");    break;
        case S_IFDIR:   strcat(buf,"d");    break;
        case S_IFBLK:   strcat(buf,"b");    break;
        case S_IFCHR:   strcat(buf,"c");    break;
        case S_IFIFO:   strcat(buf,"p");    break;
        case S_IFLNK:   strcat(buf,"l");    break;
        case S_IFSOCK:  strcat(buf,"s");    break;
        default:        strcat(buf,"?");    break;
        }
        for(int i = 0; i < 3; i++) {
            int m = (statbuf.st_mode >> 3 * (2 - i)) & 0x7;
            switch(m) {
            case 0:     strcat(buf,"---");  break;
            case 1:     strcat(buf,"--x");  break;
            case 2:     strcat(buf,"-w-");  break;
            case 3:     strcat(buf,"-wx");  break;
            case 4:     strcat(buf,"r--");  break;
            case 5:     strcat(buf,"r-x");  break;
            case 6:     strcat(buf,"rw-");  break;
            case 7:     strcat(buf,"rwx");  break;
            }
        }
        struct passwd *pwd = getpwuid(statbuf.st_uid);
        if(pwd==NULL) return -1;
        struct group *grp = getgrgid(statbuf.st_gid);
        if(grp==NULL) return -1;
        memset(buf1,0,1024);
        sprintf(buf1,"%3ld %s %s %6ld ", 
                statbuf.st_nlink,
                pwd->pw_name,
                grp->gr_name,
                statbuf.st_size);
        strcat(buf,buf1);
        struct tm* ptime = localtime(&statbuf.st_atime);
        if(ptime==NULL) return -1;
        memset(buf1,0,1024);
        sprintf(buf1,"%d/%.2d/%.2d %.2d:%.2d:%.2d %s",
                ptime->tm_year + 1900,
                ptime->tm_mon + 1,
                ptime->tm_mday,
                ptime->tm_hour,
                ptime->tm_min,
                ptime->tm_sec,
                name);
        strcat(buf,buf1);
        length=strlen(buf);
        retval=send(peerfd,&length,4,MSG_WAITALL);
        if(retval<=0) return retval;
        retval=send(peerfd,buf,strlen(buf),MSG_WAITALL);
        if(retval<=0) return retval;
        errno=0;
    }
    length=-1;
    ret=send(peerfd,&length,4,MSG_WAITALL);
    if(ret!=0) return ret;
    closedir(pdir);
    return 1;
}

int pwd_s(int peerfd)
{ 
    char buf[1024]={0};
    getcwd(buf,1024);
    int ret=send(peerfd,buf,strlen(buf)+1,MSG_WAITALL);
    if(ret<=0) return ret;
    return 1;
}

int sendbigfile(int peerfd,const char* pthname1,const char* pthname2);

int dfs_gets(int peerfd,const char* pthname1,const char* pthname2,int deep);

int getsfile_s(int peerfd,char *dir)
{
    int ret;
    struct stat statbuf;
    ret=stat(dir,&statbuf);
    if(ret==-1) return ret;
    int j=0;
    for(int i=0;i < strlen(dir);i++){
        if(dir[i]=='/'){
            j=i;
        }         
    }
    char* buff=&dir[j+1];
    if((statbuf.st_mode&S_IFMT)==S_IFDIR){
        ret=send(peerfd,"1",1,MSG_WAITALL);
        if(ret!=1) return ret;
        train_t train;
        memset(&train, 0, sizeof(train));
        train.length = strlen(buff);
        strcpy(train.buff, buff);
        ret = send(peerfd, &train, 4 + train.length, MSG_WAITALL);
        if(ret!=4 + train.length) return ret;
        ret=dfs_gets(peerfd,dir,buff,1);
        return ret;
    }
    else{
        ret=send(peerfd,"0",1,MSG_WAITALL);
        if(ret!=1) return ret;
        ret=sendbigfile(peerfd,dir,buff); 
        if(ret<=0) return ret;
        ret=send(peerfd,"2",1,MSG_WAITALL);
        return ret;
    }
}

int dfs_gets(int peerfd,const char* pthname1,const char* pthname2,int deep)
{
    DIR* pdir=opendir(pthname1);
    if(pdir==NULL) return -1;
    struct dirent* pdirent;
    errno=0;
    int ret;
    while((pdirent=readdir(pdir))!=NULL){
        if(errno!=0) return -1;
        if(pdirent->d_name[0]=='.'){
            continue;
        }
        char filename1[1024]={0};
        char filename2[1024]={0};
        sprintf(filename1,"%s/%s",pthname1,pdirent->d_name);
        sprintf(filename2,"%s/%s",pthname2,pdirent->d_name);
        if(pdirent->d_type==DT_DIR){
            ret=send(peerfd,"1",1,MSG_WAITALL);
            if(ret!=1) return ret;
            train_t train;
            memset(&train, 0, sizeof(train));
            train.length = strlen(filename2);
            strcpy(train.buff, filename2);
            ret = send(peerfd, &train, 4 + train.length, MSG_WAITALL);
            if(ret!=4 + train.length) return ret;
            dfs_gets(peerfd,filename1,filename2,deep+1);
            errno=0;
        }
        else {
            ret=send(peerfd,"0",1,MSG_WAITALL);
            if(ret!=1) return ret;
            if((ret=sendbigfile(peerfd,filename1,filename2))!=1) return ret;
            errno=0;
        }
    }
    if(deep==1){
        ret=send(peerfd,"2",1,MSG_WAITALL);
        return ret;
    }
}

int sendbigfile(int peerfd, const char* pthname1,const char* pthname2){
    int fds[2];
    pipe(fds);
    int fd=open(pthname1,O_RDWR);
    if(fd==-1) return -1;
    train_t train;
    memset(&train, 0, sizeof(train));
    train.length = strlen(pthname2);
    strcpy(train.buff, pthname2);
    int ret = send(peerfd, &train, 4 + train.length, MSG_WAITALL);
    if(ret!=4 + train.length) return ret;
    struct stat st;
    memset(&st,0,sizeof(st));
    fstat(fd, &st);
    printf("st.st_size=%ld\n",st.st_size);
    ret=send(peerfd, &st.st_size, 8, MSG_WAITALL);
    if(ret!=8) return ret;
    size_t sendSize = 0;
    while(sendSize < st.st_size){
        int ret=splice(fd,NULL,fds[1],NULL,1024,SPLICE_F_MORE);
        ret=splice(fds[0],NULL,peerfd,NULL,ret,SPLICE_F_MORE);
        if(ret<=0) return ret;
        sendSize+=ret;
    }
    return 1;
} 

int recvn(int fd,char* buff,int length)
{
    char* pbuf=buff;
    int left=length;
    int ret=0;
    while(left>0){
        ret=recv(fd,pbuf,left,MSG_WAITALL);
        if(ret<=0)  return ret;
        else{
            pbuf+=ret;
            left-=ret;
        }
    }
    return 1;
}

int putsfile_s(int peerfd)
{
    int fds[2];
    pipe(fds);
    while(1){
        char ch;
        int ret=recvn(peerfd,&ch,1);
        if(ret!=1) return ret;
        int length;
        ret = recv(peerfd, &length, 4,MSG_WAITALL);
        if(ret!=4 ) return ret;
        char pthname[1024]={0};
        ret=recvn(peerfd,pthname,length);
        printf("%s is downloading!\n",pthname);
        int fd;
        if(ch=='0'){
            fd = open(pthname, O_RDWR|O_CREAT|O_TRUNC, 0666); 
            if(fd==-1) return -1;
        }if(ch=='1'){
            ret=mkdir(pthname,0777);
            if(ret==-1) return -1;
            continue;
        }if(ch=='2') break;
        size_t filelength = 0;
        ret=recvn(peerfd, (char*)&filelength, 8);
        if(ret!=1) return ret;
        printf("%s need download %ld\n",pthname,filelength);
        size_t recvSize = 0;
        while(recvSize < filelength) {
            int lastonceSize = filelength - recvSize;
            if(filelength - recvSize < 1024) {
                ret=splice(peerfd,NULL,fds[1],NULL,lastonceSize,SPLICE_F_MORE);
                ret=splice(fds[0],NULL,fd,NULL,ret,SPLICE_F_MORE);
            }else {
                ret=splice(peerfd,NULL,fds[1],NULL,1024,SPLICE_F_MORE);
                ret=splice(fds[0],NULL,fd,NULL,ret,SPLICE_F_MORE);
            }
            if (ret<=0) return ret;
            recvSize += ret;
        }
    }
    return 1;
}

int dfs_mv(const char* pthname1,const char* pthname2,int deep)
{
    DIR* pdir=opendir(pthname1);
    if(pdir==NULL) return -1;
    struct dirent* pdirent;
    errno=0;
    int ret;
    while((pdirent=readdir(pdir))!=NULL){
        if(errno!=0) return -1;
        if(pdirent->d_name[0]=='.'){
            continue;
        }
        char buf1[1024]={0};
        char buf2[1024]={0};
        sprintf(buf1,"%s/%s",pthname1,pdirent->d_name);
        sprintf(buf2,"%s/%s",pthname2,pdirent->d_name);
        if(pdirent->d_type==DT_DIR){
            ret=mkdir(buf2,0777);
            if(ret==-1) return -1;
            dfs_mv(buf1,buf2,deep+1);
            rmdir(buf1);
            errno=0;
        }
        else {
            int src=open(buf1,O_RDWR);
            if(src==-1) return -1;
            puts("1");
            int dest=open(buf2,O_WRONLY|O_CREAT|O_TRUNC,0666);
            puts("2");
            if(dest==-1) return -1;
            char buf[1024]={0};
            ssize_t len;
            while((len=read(src,buf,1024))!=0){
                if(len<=0) return len;
                len=write(dest,buf,len);
                if(len<=0) return len;
                memset(buf,0,1024);
            }
            ret=unlink(buf1);
            if(ret==-1) return -1;
            close(src);
            close(dest);
            errno=0;
        }
    }
    if(deep==1) return 1;
}

int mv_s(char* pthname1,char* pthname2)
{
    struct stat statbuf;
    int ret=stat(pthname1,&statbuf);
    if(ret==-1) return ret;
    size_t j=0;
    for(size_t i=0;i<strlen(pthname1);i++){
        if(pthname1[i]=='/') j=i;
    }
    char* buf= pthname1+j;
    strcat(pthname2,buf);
    if((statbuf.st_mode & S_IFMT)==S_IFDIR){
        ret=mkdir(pthname2,0777);
        if(ret==-1) return -1;
        ret=dfs_mv(pthname1,pthname2,1);
        if(ret==-1) return -1;
        ret=rmdir(pthname1);
        if(ret==-1) return -1;
        return ret;
    }
    else{
        int src=open(pthname1,O_RDWR);
        if(src==-1) return -1;
        int dest=open(pthname2,O_WRONLY|O_CREAT|O_TRUNC,0666);
        if(dest==-1) return -1;
        char buf[1024]={0};
        ssize_t len=0;
        while((len=read(src,buf,1024))!=0){
            if(len<=0) return len;
            len=write(dest,buf,len);
            if(len<=0) return len;
            memset(buf,0,1024);
        }
        ret=unlink(pthname1);
        if(ret==-1) return -1;
        close(src);
        close(dest);
        return 1;
    }
}

int dfs_cp(const char* pthname1,const char* pthname2,int deep)
{
    DIR* pdir=opendir(pthname1);
    if(pdir==NULL) return -1;
    struct dirent* pdirent;
    errno=0;
    int ret;
    while((pdirent=readdir(pdir))!=NULL){
        if(errno!=0) return -1;
        if(pdirent->d_name[0]=='.'){
            continue;
        }
        char buf1[1024]={0};
        char buf2[1024]={0};
        sprintf(buf1,"%s/%s",pthname1,pdirent->d_name);
        sprintf(buf2,"%s/%s",pthname2,pdirent->d_name);
        if(pdirent->d_type==DT_DIR){
            ret=mkdir(buf2,0777);
            if(ret==-1) return -1;
            dfs_cp(buf1,buf2,deep+1);
            errno=0;
        }
        else {
            int src=open(buf1,O_RDWR);
            if(src==-1) return -1;
            puts("1");
            int dest=open(buf2,O_WRONLY|O_CREAT|O_TRUNC,0666);
            puts("2");
            if(dest==-1) return -1;
            char buf[1024]={0};
            ssize_t len;
            while((len=read(src,buf,1024))!=0){
                if(len<=0) return len;
                len=write(dest,buf,len);
                if(len<=0) return len;
                memset(buf,0,1024);
            }
            close(src);
            close(dest);
            errno=0;
        }
    }
    if(deep==1) return 1;
}

int cp_s(char* pthname1,char* pthname2)
{
    struct stat statbuf;
    int ret=stat(pthname1,&statbuf);
    if(ret==-1) return ret;
    size_t j=0;
    for(size_t i=0;i<strlen(pthname1);i++){
        if(pthname1[i]=='/') j=i;
    }
    char* buf= pthname1+j;
    strcat(pthname2,buf);
    if((statbuf.st_mode & S_IFMT)==S_IFDIR){
        ret=mkdir(pthname2,0777);
        if(ret==-1) return -1;
        ret=dfs_cp(pthname1,pthname2,1);
        return ret;
    }
    else{
        int src=open(pthname1,O_RDWR);
        if(src==-1) return -1;
        int dest=open(pthname2,O_WRONLY|O_CREAT|O_TRUNC,0666);
        if(dest==-1) return -1;
        char buf[1024]={0};
        ssize_t len=0;
        while((len=read(src,buf,1024))!=0){
            if(len<=0) return len;
            len=write(dest,buf,len);
            if(len<=0) return len;
            memset(buf,0,1024);
        }
        close(src);
        close(dest);
        return 1;
    }
}

int mkdir_s(const char* pthname)
{
    int ret=mkdir(pthname,0777);
    if(ret==-1) return -1;
    return 1;
}

int rmdir_s(const char* pthname)
{
    int ret=rmdir(pthname);
    if(ret!=1) return -1;
    return 1;
}

int dfs_rm(const char* pthname,int deep)
{
    DIR* pdir=opendir(pthname);
    if(pdir==NULL) return -1;
    struct dirent* pdirent;
    errno=0;
    int ret;
    while((pdirent=readdir(pdir))!=NULL){
        if(errno!=0) return -1;
        if(pdirent->d_name[0]=='.'){
            continue;
        }
        char buf[1024]={0};
        sprintf(buf,"%s/%s",pthname,pdirent->d_name);
        if(pdirent->d_type==DT_DIR){
            dfs_rm(buf,deep+1);
            ret=rmdir(buf);
            if(ret==-1) return -1;
            errno=0;
        }
        else {
            ret=unlink(buf);
            if(ret==-1) return -1;
            errno=0;
        }
    }
    if(deep==1) return 1;
}

int rm_s(const char* pthname)
{
    struct stat statbuf;
    int ret=stat(pthname,&statbuf);
    if(ret==-1) return ret;
    if((statbuf.st_mode & S_IFMT)==S_IFDIR){
        ret=dfs_rm(pthname,1);
        if(ret!=1) return ret;
        ret=rmdir(pthname);
        if(ret==-1) return -1;
        return 1;
    }
    else{
        ret=unlink(pthname);
        if(ret==-1) return -1;
        return 1;
    }
}

int getsfileplus_s(int peerfd, const char* pthname){
    int fds[2];
    pipe(fds);
    size_t hassend=0,filelength=0;
    int ret=recv(peerfd,&hassend,8,MSG_WAITALL);
    if(ret!=8) return ret;
    int fd=open(pthname,O_RDWR);
    if(fd==-1) return -1;
    int off_set=lseek(fd,hassend,SEEK_SET);
    if(off_set==-1) return -1;
    if(hassend==0){
        train_t train;
        memset(&train, 0, sizeof(train));
        train.length = strlen(pthname);
        strcpy(train.buff, pthname);
        int ret = send(peerfd, &train, 4 + train.length, MSG_WAITALL);
        if(ret!=4 + train.length) return ret;
    }
    struct stat st;
    memset(&st,0,sizeof(st));
    fstat(fd, &st);
    filelength=st.st_size-hassend;
    ret=send(peerfd, &filelength, 8, MSG_WAITALL);
    if(ret!=8) return ret;
    size_t sendSize = 0;
    while(sendSize < filelength){
        int ret=splice(fd,NULL,fds[1],NULL,1024,SPLICE_F_MORE);
        ret=splice(fds[0],NULL,peerfd,NULL,ret,SPLICE_F_MORE);
        if(ret<=0) return ret;
        sendSize+=ret;
    }
    return 1;
} 
